
var sb = require('./statebuffer'),
    StateBuffer = sb.StateBuffer,
    StateBufferEntry = sb.StateBufferEntry;

var dt = 1 / 60;

function Player(id, car, socket, frameId) {

    this.id = id;
    this.car = car;
    this.inputState = 0;
    this.socket = socket;
    this.spawnFrameId = frameId;
    
    this.cmdHistory = [];
    this.stateBuffer = new StateBuffer();

    // Well... :)
    this.lag = 'TODO';
    var t = Date.now;
    var self = this;
    
    socket.on('message', function(payload) {
        var m = JSON.parse(payload);
        
        switch (m.cmd) {
            case 'moves':
                Array.prototype.push.apply(self.cmdHistory, m.moves);
                break;
            default: break;
        }
    });
    
    socket.send(JSON.stringify({
        clientId: id,
        frameId: frameId,
        m: 'init'
    }));
};

Player.prototype.addStateBufferEntry = function(frameId) {
    this.stateBuffer.add(new StateBufferEntry(
        frameId,
        this.car.phyObj.clone(),
        this.car.keys,
        this.car.haltedTicks,
        this.car.forwardVec.clone())
    );
};

Player.prototype.applyCommands = function(game) {
    var
        cmd,
        nextCmd,
        state,
        iter
        ;
        
    if (this.cmdHistory.length === 0) return;
    
    if (this.cmdHistory[this.cmdHistory.length - 1].frameId >= game.time.getFrameId()) return;
    
    // Get statebuffer for states between oldest command and now
    while ((!iter) && (this.cmdHistory.length > 0)) {
        cmd = this.cmdHistory.splice(0, 1)[0];
        try {
            iter = this.stateBuffer.iterator(cmd.frameId); //???
        } catch (e) {
            console.error('Too old, cannot remember ' + cmd.frameId);
            /*Buffer doesn't remember the requested frame*/
        }
    }
    
    // As far as we know, there's nothing to correct
    if (!iter)
        return;

    while ((state = iter.next())) {
        while (cmd && (cmd.frameId === (state.frameId - 1))) {
            if (cmd.cmd === 'keyup') {
                state.unsetKey(cmd.key, cmd.frameId);
            } else if (cmd.cmd === 'keydown') {
                state.setKey(cmd.key, cmd.frameId);
            }
            cmd = this.cmdHistory.splice(0, 1)[0];
        }
        step({
            state: {
                entities: [state]
            },
            groundMap: game.groundMap
        }, dt);
    }
    
    // Correct "live" entity
    state = this.stateBuffer.data[this.stateBuffer.index].clone();
    
    this.car.phyObj = state.phyObj.clone();
    this.car.haltedTicks = state.haltedTicks;
    this.car.keys = state.keys;
    this.car.upVec = state.upVec.clone();
    this.car.rightVec = state.rightVec.clone();
    this.car.forwardVec = state.forwardVec.clone();
    this.car.centerVec = state.centerVec.clone();

    step({
        state: {
            entities: [this.car]
        },
        groundMap: game.groundMap
    }, dt);
    
};

module.exports = Player;
